package org.giiwa.thirdlogin.web;

import javax.servlet.http.HttpServletResponse;

import org.giiwa.core.base.Http;
import org.giiwa.core.base.Http.Response;
import org.giiwa.core.bean.X;
import org.giiwa.core.bean.Helper.V;
import org.giiwa.core.conf.Global;
import org.giiwa.core.json.JSON;
import org.giiwa.core.task.Task;
import org.giiwa.framework.bean.AuthToken;
import org.giiwa.framework.bean.Role;
import org.giiwa.framework.bean.User;
import org.giiwa.framework.web.Model;
import org.giiwa.framework.web.Path;

import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayUserDetail;
import com.alipay.api.request.AlipayOpenAuthTokenAppRequest;
import com.alipay.api.request.AlipayUserGetRequest;
import com.alipay.api.response.AlipayOpenAuthTokenAppResponse;
import com.alipay.api.response.AlipayUserGetResponse;

public class thirdlogin extends Model {

  private static String github_token   = "https://github.com/login/oauth/access_token";
  private static String github_user    = "https://api.github.com/user?access_token=%s";
  private static String wechat_token   = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code";
  private static String wechat_user    = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s";
  private static String sina_token     = "https://api.weibo.com/oauth2/access_token";
  private static String sina_user      = "https://api.weibo.com/2/users/show.json?access_token=%s&uid=%s";
  private static String alipay_gateway = "https://openapi.alipay.com/gateway.do";

  @Path(path = "appid")
  public void appid() {

    String partner = this.getString("partner");
    JSON jo = JSON.create();
    jo.put("appid", Global.getString("thirdlogin." + partner + ".appid", ""));
    jo.put(X.STATE, HttpServletResponse.SC_OK);
    this.response(jo);

  }

  @Path(path = "alipay", log = Model.METHOD_GET | Model.METHOD_POST)
  public void alipay() {
    String code = this.getString("app_auth_code");

    try {
      final AlipayClient alipayClient = new DefaultAlipayClient(alipay_gateway,
          Global.getString("thirdlogin.alipay.appid", ""), Global.getString("thirdlogin.alipay.app_private_key", ""),
          "json", "GBK", Global.getString("thirdlogin.alipay.alipay_public_key", ""));

      /**
       * get auth_token and user_id
       */
      AlipayOpenAuthTokenAppRequest request = new AlipayOpenAuthTokenAppRequest();
      JSON jo = JSON.create();
      jo.put("code", code);
      jo.put("grant_type", "authorization_code");
      request.setBizContent(jo.toString());
      final AlipayOpenAuthTokenAppResponse r = alipayClient.execute(request);
      if (r.isSuccess()) {
        String uid = r.getUserId();
        User u = User.load("alipay//" + uid);
        if (u == null) {
          String token = r.getAppAuthToken();

          AlipayUserGetRequest r1 = new AlipayUserGetRequest();
          r1.setFields("alipay_user_id,user_status,user_type,certified,real_name,logon_id,sex");
          AlipayUserGetResponse resp1 = alipayClient.execute(r1, token);
          AlipayUserDetail d1 = resp1.getAlipayUserDetail();

          V v = V.create();
          v.set("name", "alipay//" + uid);
          v.set("nickname", d1.getRealName());
          long id = User.create(v);
          u = User.loadById(id);
        } else {
          final User u1 = u;
          new Task() {

            @Override
            public void onExecute() {
              try {
                String token = r.getAppAuthToken();

                AlipayUserGetRequest r1 = new AlipayUserGetRequest();
                r1.setFields("alipay_user_id,user_status,user_type,certified,real_name,logon_id,sex");
                AlipayUserGetResponse resp1 = alipayClient.execute(r1, token);
                AlipayUserDetail d1 = resp1.getAlipayUserDetail();

                V v = V.create();
                v.set("nickname", d1.getRealName());
                User.update(u1.getId(), v);

                User u = User.loadById(u1.getId());
                setUser(u);

              } catch (Exception e) {
                log.error(e.getMessage(), e);
              }
            }

          }.schedule(0);
        }
        this.setUser(u);

        if (isAjax()) {
          jo = JSON.create();
          jo.put(X.STATE, HttpServletResponse.SC_OK);
          jo.put("sid", sid());
          if (Global.getInt("user.token", 1) == 1) {
            AuthToken t = AuthToken.update(u.getId(), sid(), this.getRemoteHost());
            if (t != null) {
              jo.put("token", t.getToken());
              jo.put("expired", t.getExpired());
              jo.put(X.STATE, HttpServletResponse.SC_OK);
            } else {
              jo.put(X.MESSAGE, "create authtoken error");
              jo.put(X.STATE, HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            }
          }
          this.response(jo);
        } else {
          this.redirect("/user/go");
        }

        return;
      }

      if (isAjax()) {
        jo = JSON.create();
        jo.put(X.STATE, HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        jo.put(X.MESSAGE, r.getBody());
        this.response(jo);

      } else {
        this.println(r.getBody());
      }

    } catch (Exception e) {
      this.error(e);

    }

  }

  @Path()
  public void onGet() {

  }

  @Path(path = "sina", log = Model.METHOD_GET | Model.METHOD_POST)
  public void sina() {
    String code = this.getString("code");
    JSON jo = JSON.create();
    jo.put("client_id", Global.getString("thirdlogin.sina.appid", X.EMPTY));
    jo.put("client_secret", Global.getString("thirdlogin.sina.secret", X.EMPTY));
    jo.put("code", code);
    jo.put("redirect_uri", Global.getString("site.url", X.EMPTY) + "/thridlogin/sina");

    Response r = Http.post(sina_token, jo);
    jo = JSON.fromObject(r.body);
    if (jo.has("access_token")) {
      final String token = jo.getString("access_token");
      final String uid = jo.getString("uid");
      User u = User.load("sina//" + uid);
      if (u == null) {

        String url = String.format(sina_user, token, uid);
        r = Http.get(url);
        jo = JSON.fromObject(r.body);
        String nickname = jo.getString("screen_name");
        String photo = jo.getString("profile_image_url");
        V v = V.create("name", "sina//" + uid);
        v.set("nickname", nickname);
        v.set("photo", photo);
        long id = User.create(v);
        u = User.loadById(id);

        String role = Global.getString("user.role", "N/A");
        Role r1 = Role.loadByName(role);
        if (r != null) {
          u.setRole(r1.getId());
        }
      } else {
        final User u1 = u;
        new Task() {

          @Override
          public void onExecute() {
            String url = String.format(sina_user, token, uid);
            Response r = Http.get(url);
            JSON jo = JSON.fromObject(r.body);
            String nickname = jo.getString("screen_name");
            String photo = jo.getString("profile_image_url");

            V v = V.create();
            v.set("nickname", nickname);
            v.set("photo", photo);

            User.update(u1.getId(), v);

            User u = User.loadById(u1.getId());
            setUser(u);
          }
        }.schedule(0);

      }

      this.setUser(u);
      if (isAjax()) {
        jo = JSON.create();
        jo.put(X.STATE, HttpServletResponse.SC_OK);
        jo.put("sid", sid());
        if (Global.getInt("user.token", 1) == 1) {
          AuthToken t = AuthToken.update(u.getId(), sid(), this.getRemoteHost());
          if (t != null) {
            jo.put("token", t.getToken());
            jo.put("expired", t.getExpired());
            jo.put(X.STATE, HttpServletResponse.SC_OK);
          } else {
            jo.put(X.MESSAGE, "create authtoken error");
            jo.put(X.STATE, HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
          }
        }
        this.response(jo);
      } else {
        this.redirect("/user/go");
      }

      return;
    }

    if (isAjax()) {
      jo = JSON.create();
      jo.put(X.STATE, HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
      jo.put(X.MESSAGE, r.body);
      this.response(jo);

    } else {
      this.println(r.body);
    }
  }

  @Path(path = "wechat", log = Model.METHOD_GET | Model.METHOD_POST)
  public void wechat() {

    String code = this.getString("code");
    String url = String.format(wechat_token, Global.getString("thirdlogin.wechat.appid", X.EMPTY),
        Global.getString("thirdlogin.wechat.secret", X.EMPTY), code);

    Response r = Http.get(url);
    JSON jo = JSON.fromObject(r.body);
    if (jo.has("access_token")) {
      final String token = jo.getString("access_token");
      final String openid = jo.getString("openid");
      String unionid = jo.getString("unionid");

      User u = User.load("wechat//" + unionid);
      if (u == null) {

        url = String.format(wechat_user, token, openid);
        r = Http.get(url);

        jo = JSON.fromObject(r.body);
        String nickname = jo.getString("nickname");
        String photo = jo.getString("headimgurl");

        V v = V.create();
        v.set("name", "wechat//" + unionid);
        v.set("nickname", nickname);
        v.set("photo", photo);
        long id = User.create(v);
        u = User.loadById(id);

        String role = Global.getString("user.role", "N/A");
        Role r1 = Role.loadByName(role);
        if (r != null) {
          u.setRole(r1.getId());
        }

      } else {
        final User u1 = u;
        new Task() {

          @Override
          public void onExecute() {
            String url = String.format(wechat_user, token, openid);
            Response r = Http.get(url);

            JSON jo = JSON.fromObject(r.body);
            String nickname = jo.getString("nickname");
            String photo = jo.getString("headimgurl");

            V v = V.create();
            v.set("nickname", nickname);
            v.set("photo", photo);

            User.update(u1.getId(), v);

            User u = User.loadById(u1.getId());
            setUser(u);

          }
        }.schedule(0);
      }
      this.setUser(u);

      if (isAjax()) {
        jo = JSON.create();
        jo.put(X.STATE, HttpServletResponse.SC_OK);
        jo.put("sid", sid());
        if (Global.getInt("user.token", 1) == 1) {
          AuthToken t = AuthToken.update(u.getId(), sid(), this.getRemoteHost());
          if (t != null) {
            jo.put("token", t.getToken());
            jo.put("expired", t.getExpired());
            jo.put(X.STATE, HttpServletResponse.SC_OK);
          } else {
            jo.put(X.MESSAGE, "create authtoken error");
            jo.put(X.STATE, HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
          }
        }
        this.response(jo);
      } else {
        this.redirect("/user/go");
      }
      return;
    }

    if (isAjax()) {
      jo = JSON.create();
      jo.put(X.STATE, HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
      jo.put(X.MESSAGE, r.body);
      this.response(jo);

    } else {
      this.println(r.body);
    }
  }

  @Path(path = "github", log = Model.METHOD_GET | Model.METHOD_POST)
  public void github() {
    String code = this.getString("code");
    JSON jo = JSON.create();
    jo.put("client_id", Global.getString("thirdlogin.github.appid", X.EMPTY));
    jo.put("client_secret", Global.getString("thirdlogin.github.secret", X.EMPTY));
    jo.put("code", code);

    JSON h1 = JSON.create();
    h1.put("Accept", "application/json");
    Response r = Http.post(github_token, null, h1, jo);
    jo = JSON.fromObject(r.body);
    if (jo.has("access_token")) {
      String token = jo.getString("access_token");
      String url = String.format(github_user, token);
      r = Http.get(url);
      jo = JSON.fromObject(r.body);

      if (jo.has("id")) {
        String id = jo.getString("id");
        final String photo = jo.getString("avatar_url");
        final String nickname = jo.getString("name");
        User u = User.load("github//" + id);
        if (u == null) {
          V v = V.create("name", "github//" + id);
          v.set("photo", photo);
          v.set("nickname", nickname);
          long uid = User.create(v);
          u = User.loadById(uid);

          String role = Global.getString("user.role", "N/A");
          Role r1 = Role.loadByName(role);
          if (r != null) {
            u.setRole(r1.getId());
          }

        } else {
          V v = V.create();
          v.set("photo", photo);
          v.set("nickname", nickname);

          User.update(u.getId(), v);

          u = User.loadById(u.getId());
          setUser(u);

        }

        this.setUser(u);
        if (isAjax()) {
          jo = JSON.create();
          jo.put(X.STATE, HttpServletResponse.SC_OK);
          jo.put("sid", sid());
          if (Global.getInt("user.token", 1) == 1) {
            AuthToken t = AuthToken.update(u.getId(), sid(), this.getRemoteHost());
            if (t != null) {
              jo.put("token", t.getToken());
              jo.put("expired", t.getExpired());
              jo.put(X.STATE, HttpServletResponse.SC_OK);
            } else {
              jo.put(X.MESSAGE, "create authtoken error");
              jo.put(X.STATE, HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            }
          }
          this.response(jo);
        } else {
          this.redirect("/user/go");
        }
        return;
      }
    }

    if (isAjax()) {
      jo = JSON.create();
      jo.put(X.STATE, HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
      jo.put(X.MESSAGE, r.body);
      this.response(jo);

    } else {
      this.println(r.body);
    }
  }
}
